package com.zsl.swing.redis.desktop.demo;

import com.alibaba.fastjson.JSON;
import com.zsl.swing.redis.desktop.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
public class HdlOpenPlatFormDemo {

    public static void test_01() {
        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .readTimeout(15, TimeUnit.SECONDS)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .writeTimeout(15, TimeUnit.SECONDS)
                    .build();

            String url = "https://open.kiwa-tech.com/queue/basic";
            String tokenUrl = "https://open.kiwa-tech.com/oauth/token?grant_type=client_credentials&scope=sever&client_id=hdl5DzOVNcG1ImNE9&client_secret=phkKX1ZTTjKCeP4IxCQm8Fs5RWEzPO01B7Lh3FgQ9VWvdkBQ2d";

            /*String tokenBody = HttpUtil.createPost(tokenUrl).execute().body();
            Map map = JSON.parseObject(tokenBody, Map.class);
            String token = (String) map.get("access_token");*/
            Response post = client.newCall(buildRequest(tokenUrl, null, null, "POST")).execute();
            Map map = JSON.parseObject(post.body().string(), Map.class);
            String token = (String) map.get("access_token");
            log.info("token是{}", token);

            Map<String, String> header = new HashMap<>();
            header.put("Authorization", token);
            header.put("method", "5104");
            header.put("requestId", UUID.randomUUID().toString());
            header.put("content-type", "application/json; charset=utf-8");
            header.put("x-ca-timestamp", System.currentTimeMillis() + "");

            Map<String, String> body = new HashMap<>();
            body.put("mobile", "18301156308");

            String string = buildStringToSign(header, body);

            System.out.println("签名串：" + string);
//            String pwd = "O6VY7AJ3BL3AO6DY503515DU4SP7DQ6T8R5W7QD0";
            String pwd = "0VI1532BK178XI7I840IB10U1UMCPI1158BQJ86K";
            Mac hmacSha256 = Mac.getInstance("HmacSHA256");
            byte[] keyBytes = pwd.getBytes(Charset.forName("UTF-8"));
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));

            byte[] md5Result = hmacSha256.doFinal(string.getBytes(Charset.forName("UTF-8")));
            String sign = Base64.getEncoder().encodeToString(md5Result);
            System.out.println(sign);
            header.put("x-ca-signature", sign);
            Response response = client.newCall(buildRequest(url, header, body, "POST")).execute();
            log.info(response.body().string());
        } catch (Exception e) {
            log.error("异常", e);
        }
    }

    /**
     *  将headers合成一个字符串
     *  需要注意的是，HTTP头需要按照字母排序加入签名字符串
     *  同时所有加入签名的头的列表，需要用逗号分隔形成一个字符串，加入一个新HTTP头@"X-Ca-Signature-Headers"
     */
    private static String buildHeaders(Map<String, String> apiHttpMessage) {
        //使用TreeMap,默认按照字母排序
        Map<String, String> headersToSign = new TreeMap<String, String>();
        StringBuilder signHeadersStringBuilder = new StringBuilder();
        int flag = 0;
        for (Map.Entry<String, String> header : apiHttpMessage.entrySet()) {
            if (header.getKey().startsWith("x-ca-")) {
                if(header.getKey().equals("x-ca-signature")
                        || header.getKey().equals("x-ca-signature-headers")){
                    continue;
                }

                if (flag != 0) {
                    signHeadersStringBuilder.append(",");
                }
                flag++;
                signHeadersStringBuilder.append(header.getKey());
                headersToSign.put(header.getKey(), apiHttpMessage.get(header.getKey()));
            }
        }

        //同时所有加入签名的头的列表，需要用逗号分隔形成一个字符串，加入一个新HTTP头@"X-Ca-Signature-Headers"
        apiHttpMessage.put("x-ca-signature-headers", signHeadersStringBuilder.toString());

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> e : headersToSign.entrySet()) {
            sb.append(e.getKey()).append(':').append(e.getValue()).append("\n");
        }
        log.info("header是{}", sb.toString());
        return sb.toString();
    }

    /**
     * 将path、queryParam、formParam合成一个字符串
     */
    private static String buildResource(Map<String, String> body) {
        StringBuilder result = new StringBuilder();
        result.append("/queue/basic");

        //使用TreeMap,默认按照字母排序
        TreeMap<String , String> parameter = new TreeMap<String , String>();
        parameter.putAll(body);

        if(parameter.size() > 0) {
            result.append("?");
            boolean isFirst = true;
            for (String key : parameter.keySet()) {
                if (isFirst == false) {
                    result.append("&");
                } else {
                    isFirst = false;
                }
                result.append(key);
                String value = parameter.get(key);
                if(null != value && !"".equals(value)){
                    result.append("=").append(value);
                }
            }
        }
        return result.toString();
    }

    /**
     * 将Request中的httpMethod、headers、path、queryParam、formParam合成一个字符串
     */
    public static String buildStringToSign(Map<String, String> header, Map<String, String> body) {
        StringBuilder sb = new StringBuilder();
        sb.append("POST").append("\n");

        //如果有@"Accept"头，这个头需要参与签名
        if (header.get("accept") != null) {
            sb.append(header.get("accept"));
        }
        sb.append("\n");

        //如果有@"Content-MD5"头，这个头需要参与签名
        if (header.get("content-md5") != null) {
            sb.append(header.get("content-md5"));
        }
        sb.append("\n");

        //如果有@"Content-Type"头，这个头需要参与签名
        if (header.get("content-type") != null) {
            sb.append(header.get("content-type"));
        }
        sb.append("\n");

        //签名优先读取HTTP_CA_HEADER_DATE，因为通过浏览器过来的请求不允许自定义Date（会被浏览器认为是篡改攻击）
        if (header.get("date") != null) {
            sb.append(header.get("date"));
        }
        sb.append("\n");

        //将headers合成一个字符串
        sb.append(buildHeaders(header));

        //将path、queryParam、formParam合成一个字符串
        sb.append(buildResource(body));
        log.info("最终{}", sb.toString());
        return sb.toString();
    }

    private static Request buildRequest(String url, Map<String, String> headerMap, Map<String, String> param, String requestMethod) {
        Request.Builder requestBuilder = new Request.Builder();
        //处理请求头
        if (!CollectionUtils.isEmpty(headerMap)) {
            requestBuilder.headers(buildHeaders2(headerMap));
        }
        //处理请求参数
        if (!CollectionUtils.isEmpty(param)) {
            if (Objects.equals(requestMethod, "GET")) {
                url += buildUrlPram(param);
                requestBuilder.get();
            } else if (Objects.equals(requestMethod, "POST")) {
                requestBuilder.post(RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(param)));
            }
        }
        return requestBuilder.url(url).build();
    }

    private static Headers buildHeaders2(Map<String, String> headerMap){
        Headers.Builder headersbuilder = new Headers.Builder();
        if(!CollectionUtils.isEmpty(headerMap)) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headersbuilder.add(entry.getKey(), entry.getValue());
            }
        }
        return headersbuilder.build();
    }
    private static String buildUrlPram(Map<String, String> param) {
        StringBuilder sb = new StringBuilder();
        sb.append("?");
        int first = 1;
        for (Map.Entry<String, String> entry : param.entrySet()) {
            if (first != 1) {
                sb.append("&");
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue());
            first++;
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        test_01();
    }
}
